
// DES.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

// 记录所有的子秘钥
int eachKey[16][48];

int boxS[8][4][16] = { // S1
    {{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
     {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
     {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
     {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}},
    // S2
    {{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
     {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
     {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
     {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}},
    // S3
    {{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
     {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
     {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
     {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}},
    // S4
    {{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
     {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
     {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
     {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}},
    // S5
    {{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
     {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
     {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
     {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}},
    // S6
    {{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
     {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
     {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
     {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}},
    // S7
    {{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
     {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
     {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
     {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}},
    // S8
    {{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
     {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
     {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
     {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}}};

// 记录左移次数
int leftMove[16] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};

int C[28] = {0}, D[28] = {0};
int L[32] = {1}, R[32] = {1};

// p置换
int P[32] = {16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25};

// E扩展
int biteChoiceLabel[48] = {32, 1, 2, 3, 4, 5,
                           4, 5, 6, 7, 8, 9,
                           8, 9, 10, 11, 12, 13,
                           12, 13, 14, 15, 16, 17,
                           16, 17, 18, 19, 20, 21,
                           20, 21, 22, 23, 24, 25,
                           24, 25, 26, 27, 28, 29,
                           28, 29, 30, 31, 32, 1};

// 秘钥置换
int keySwap[8][6] = {{14, 17, 11, 24, 1, 5},
                     {3, 28, 15, 6, 21, 10},
                     {23, 19, 12, 4, 26, 8},
                     {16, 7, 27, 20, 13, 2},
                     {41, 52, 31, 37, 47, 55},
                     {30, 40, 51, 45, 33, 48},
                     {44, 49, 39, 56, 34, 53},
                     {46, 42, 50, 36, 29, 32}};

// 密文初始置换
int IP[8][8] = {{
                    58,
                    50,
                    42,
                    34,
                    26,
                    18,
                    10,
                    2,
                },
                {
                    60,
                    52,
                    44,
                    36,
                    28,
                    20,
                    12,
                    4,
                },
                {
                    62,
                    54,
                    46,
                    38,
                    30,
                    22,
                    14,
                    6,
                },
                {
                    64,
                    56,
                    48,
                    40,
                    32,
                    24,
                    16,
                    8,
                },
                {
                    57,
                    49,
                    41,
                    33,
                    25,
                    17,
                    9,
                    1,
                },
                {
                    59,
                    51,
                    43,
                    35,
                    27,
                    19,
                    11,
                    3,
                },
                {
                    61,
                    53,
                    45,
                    37,
                    29,
                    21,
                    13,
                    5,
                },
                {63, 55, 47, 39, 31, 23, 15, 7}};

// 密文逆置换
int IP_1[8][8] = {{40, 8, 48, 16, 56, 24, 64, 32},
                  {39, 7, 47, 15, 55, 23, 63, 31},
                  {38, 6, 46, 14, 54, 22, 62, 30},
                  {37, 5, 45, 13, 53, 21, 61, 29},
                  {36, 4, 44, 12, 52, 20, 60, 28},
                  {35, 3, 43, 11, 51, 19, 59, 27},
                  {34, 2, 42, 10, 50, 18, 58, 26},
                  {33, 1, 41, 9, 49, 17, 57, 25}};

// 64->56选择
int PC_1[8][7] = {{57, 49, 41, 33, 25, 17, 9},
                  {1, 58, 50, 42, 34, 26, 18},
                  {10, 2, 59, 51, 43, 35, 27},
                  {19, 11, 3, 60, 52, 44, 36},
                  {63, 55, 47, 39, 31, 23, 15},
                  {7, 62, 54, 46, 38, 30, 22},
                  {14, 6, 61, 53, 45, 37, 29},
                  {21, 13, 5, 28, 20, 12, 4}};

// 初始置换IP
void InitIP(int **input)
{
    int s[64];
    int c = 0;
    for (int i = 0; i < 8; i++)
        for (int j = 0; j < 8; j++)
        {
            s[c++] = input[i][j];
        }
    int **newIP = new int *[8];
    for (int i = 0; i < 8; i++)
        newIP[i] = new int[8];

    for (int i = 0; i < 8; i++)
    {
        for (int j = 0; j < 8; j++)
        {
            int loc = IP[i][j] - 1; // 因为从1开始，这里下标减一
            newIP[i][j] = s[loc];
        }
    }
    int l = 0, m = 0;
    for (int i = 0; i < 8; i++)
        for (int j = 0; j < 8; j++)
        {
            if (i * 8 + j < 32)
                L[l++] = newIP[i][j];
            else
                R[m++] = newIP[i][j];
        }
}

// 逆初始置换
void reverse()
{
    int temp[64];
    int a[64];
    for (int i = 0; i < 32; i++)
    {
        temp[i] = L[i];
        temp[i + 32] = R[i];
    }

    int l = 0, m = 0;
    for (int i = 0; i < 8; i++)
    {
        for (int j = 0; j < 8; j++)
        {
            a[l++] = temp[IP_1[i][j] - 1];
        }
    }
    l = 0;
    for (int i = 0; i < 64; i++)
        if (i < 32)
            L[l++] = a[i];
        else
            R[m++] = a[i];
}

// 操作函数f
int *f(int n, int flag)
{
    int *result = new int[32];
    int a[48];
    int temp[56];
    int newKey[48];
    for (int i = 0; i < 28; i++)
    {
        temp[i] = C[i];
        temp[i + 28] = D[i];
    }
    int l = 0;
    if (flag == 0)
    {
        for (int i = 0; i < 8; i++)
        {
            for (int j = 0; j < 6; j++)
            {
                int loc = keySwap[i][j];
                newKey[l++] = temp[loc - 1];
                eachKey[15 - n][l - 1] = newKey[l - 1]; // 记录加密时的全部子秘钥
            }
        }
    }
    else
    {
        for (int i = 0; i < 48; i++)
            newKey[i] = eachKey[n][i];
    }
    int newR[48];
    for (int i = 0; i < 48; i++)
        newR[i] = R[biteChoiceLabel[i] - 1];
    for (int i = 0; i < 48; i++)
        a[i] = (newKey[i] + newR[i]) % 2;
    int b[8][6];
    int r[8];
    l = 0;
    int m = 0;
    int k = 0;
    for (int i = 0; i < 48; i++)
    {
        b[l][m] = a[i];
        if ((i + 1) % 6 == 0)
        {
            int first = b[l][0] * 2 + b[l][5];
            int second = b[l][1] * 8 + b[l][2] * 4 + b[l][3] * 2 + b[l][4];
            r[l] = boxS[l][first][second];
            l++;
            m = 0;
        }
        else
            m++;
    }
    int c[8][4];
    l = 0;
    for (int i = 0; i < 8; i++)
    {
        int ti = 0;
        int aa = r[i] / 8;
        int bb = (r[i] - aa * 8) / 4;
        int cc = (r[i] - aa * 8 - bb * 4) / 2;
        int dd = r[i] - aa * 8 - bb * 4 - cc * 2;
        c[i][0] = aa;
        c[i][1] = bb;
        c[i][2] = cc;
        c[i][3] = dd;
    }
    int tempP[32];
    for (int i = 0; i < 8; i++)
        for (int j = 0; j < 4; j++)
        {
            tempP[l++] = c[i][j];
        }
    for (int i = 0; i < 32; i++)
        result[i] = tempP[P[i] - 1];
    return result;
}

// 交换处理
void swap(int n, int flag)
{
    int tempL[32], tempR[32];
    int *Result = new int[32];
    // 数据备份
    for (int i = 0; i < 32; i++)
    {
        tempR[i] = R[i];
        tempL[i] = L[i];
    }
    Result = f(n, flag);
    // 数据更新计
    for (int i = 0; i < 32; i++)
    {
        L[i] = tempR[i];
        R[i] = (tempL[i] + Result[i]) % 2;
    }
    if (n == 15)
    {
        for (int i = 0; i < 32; i++)
        {
            int temp = L[i];
            L[i] = R[i];
            R[i] = temp;
        }
    }
}

// 产生第一轮秘钥（64位->56位)
int **firstKey(int **key)
{
    int **fk = new int *[8];
    for (int i = 0; i < 8; i++)
        fk[i] = new int[7];
    int nk[64];
    int s = 0;
    int l = 0, m = 0;
    for (int i = 0; i < 8; i++)
        for (int j = 0; j < 8; j++)
            nk[s++] = key[i][j];
    for (int i = 0; i < 8; i++)
    {
        for (int j = 0; j < 7; j++)
        {
            int loc = PC_1[i][j] - 1;
            fk[i][j] = nk[loc];
            if (l < 28)
                C[l++] = nk[loc];
            else
                D[m++] = nk[loc];
        }
    }
    return fk;
}

// 循环产生子秘钥
void nextKeyLeft(int n)
{
    int times = leftMove[n];
    for (int i = 0; i < times; i++)
    {
        int C0 = C[0];
        int D0 = D[0];
        for (int j = 1; j < 28; j++)
        {
            C[j - 1] = C[j];
            D[j - 1] = D[j];
        }
        C[27] = C0;
        D[27] = D0;
    }
}

// 十六进制输入转二进制
int **hxTobin(string input)
{
    int a[64];
    int x[16];
    int **init_letters = new int *[8];
    for (int i = 0; i < 8; i++)
        init_letters[i] = new int[8];
    int j = 0;
    for (int i = 0; i < 16; i++)
    {
        if (input[i] >= '0' && input[i] <= '9')
            x[i] = input[i] - 48;
        else if (input[i] >= 'A' && input[i] <= 'Z')
            x[i] = input[i] - 55;
        else
            x[i] = input[i] - 87;
    }
    for (int i = 0; i < 16; i++)
    {
        int aa = x[i] / 8;
        int bb = (x[i] - aa * 8) / 4;
        int cc = (x[i] - aa * 8 - bb * 4) / 2;
        int dd = x[i] - aa * 8 - bb * 4 - cc * 2;
        a[j] = aa;
        a[j + 1] = bb;
        a[j + 2] = cc;
        a[j + 3] = dd;
        j = j + 4;
    }

    int l = 0;
    for (int i = 0; i < 8; i++)
    {
        for (j = 0; j < 8; j++)
        {
            init_letters[i][j] = a[l++];
        }
    }
    return init_letters;
}

// 二进制密文转十六进制密文
string binTohx(int a[])
{
    string res;
    res.resize(16);
    int j = 0;
    for (int i = 0; i < 64; i += 4)
    {
        int b = a[i] * 8 + a[i + 1] * 4 + a[i + 2] * 2 + a[i + 3];
        if (b < 10)
            res[j] = b + '0';
        else
        {
            switch (b)
            {
            case 10:
                res[j] = 'a';
                break;
            case 11:
                res[j] = 'b';
                break;
            case 12:
                res[j] = 'c';
                break;
            case 13:
                res[j] = 'd';
                break;
            case 14:
                res[j] = 'e';
                break;
            case 15:
                res[j] = 'f';
                break;
            }
        }
        j++;
    }
    return res;
}

// 解密过程
void decode(string res)
{
    int **re = new int *[8];
    for (int i = 0; i < 8; i++)
        re[i] = new int[8];
    re = hxTobin(res);
    InitIP(re);
    for (int i = 0; i < 16; i++)
    {
        swap(i, 1);
    }
    reverse();
    int a[64];
    for (int i = 0; i < 32; i++)
    {
        a[i] = L[i];
        a[i + 32] = R[i];
    }
    string input;
    input = binTohx(a);
    std::cout << input << endl
              << endl;
    ;
}

int main()
{
    string letters;
    string keys;
    string words;
    char flag = 'n';
    int miwen[64];
    ifstream file;
    file.open("test.txt");
    int **fir = new int *[8];
    for (int i = 0; i < 8; i++)
        fir[i] = new int[8];
    cout << "--------- Begin(y/n)? ----------" << endl;
    cin >> flag;
    while (flag == 'y' && !file.eof())
    {
        std::cout << "---------- 读入密文: ----------" << endl;
        if (!file)
        {
            std::cout << "---------- 读取失败 ----------" << endl;
            exit(0);
        }
        getline(file, letters);
        std::cout << "明文: " << letters << endl
                  << endl;
        std::cout << "---------- 读入秘钥: ----------" << endl;
        getline(file, keys);
        std::cout << "秘钥: " << keys << endl
                  << endl;
        fir = hxTobin(keys);
        int **getLetters = new int *[8];
        for (int i = 0; i < 8; i++)
            getLetters[i] = new int[8];
        getLetters = hxTobin(letters);
        InitIP(getLetters);
        int **fk = new int *[8];
        for (int i = 0; i < 8; i++)
            fk[i] = new int[7];
        for (int i = 0; i <= 16; i++)
        {
            if (i == 0)
            {
                fk = firstKey(fir);
            }
            else
            {
                nextKeyLeft(i - 1);
                swap(i - 1, 0);
            }
        }
        reverse();
        int k = 0;
        for (int i = 0; i < 32; i++)
        {
            miwen[k++] = L[i];
        }
        for (int i = 0; i < 32; i++)
        {
            miwen[k++] = R[i];
        }
        words = binTohx(miwen);
        std::cout << "密文: " << words << endl;
        std::cout << "----------  解密中  ----------" << endl;
        decode(words);
        std::cout << "-----------  继续(y/n) ---------" << endl;
        std::cin >> flag;
    }
    std::cout << "---------- End! ----------" << endl;
    return 0;
}